Get your production-ready VPC infrastructure up and running in just a few steps.
Prerequisites
Before you begin, ensure you have:
Terraform installed (version 0.12 or later recommended)
AWS credentials configured
Basic understanding of VPC concepts
Basic Deployment
Create a Terraform configuration file
Create a new file named main.tf with the following content: module "vpc" {
source = "github.com/Planview/tf_aws_vpc"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = [ "us-west-2a" , "us-west-2b" , "us-west-2c" ]
private_subnets = [ "10.0.1.0/24" , "10.0.2.0/24" , "10.0.3.0/24" ]
public_subnets = [ "10.0.101.0/24" , "10.0.102.0/24" , "10.0.103.0/24" ]
enable_nat_gateway = true
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Terraform = "true"
Environment = "production"
}
}
This creates a basic multi-AZ VPC with:
3 public subnets (one per AZ)
3 private subnets (one per AZ)
NAT Gateways for private subnet internet access
DNS support enabled
Add outputs to reference VPC resources
Add this to your main.tf to access the created resources: output "vpc_id" {
description = "The ID of the VPC"
value = module . vpc . vpc_id
}
output "private_subnets" {
description = "List of IDs of private subnets"
value = module . vpc . private_subnets
}
output "public_subnets" {
description = "List of IDs of public subnets"
value = module . vpc . public_subnets
}
Initialize Terraform
Run the following command to download the module:
Review the plan
See what resources will be created: You should see approximately 15+ resources being created, including:
1 VPC
6 subnets (3 public, 3 private)
1 Internet Gateway
3 NAT Gateways
Route tables and associations
Apply the configuration
Create the infrastructure: Type yes when prompted to confirm. NAT Gateways cost approximately 0.045 / h o u r ( 0.045/hour ( 0.045/ h o u r ( 32/month) per gateway. This basic configuration creates 3 NAT Gateways. Consider using single_nat_gateway = true for development environments to reduce costs.
Verify the outputs
After the deployment completes, you’ll see the outputs: Outputs:
vpc_id = "vpc-1234567890abcdef0"
private_subnets = [
"subnet-1234567890abcdef0" ,
"subnet-1234567890abcdef1" ,
"subnet-1234567890abcdef2" ,
]
public_subnets = [
"subnet-1234567890abcdef3" ,
"subnet-1234567890abcdef4" ,
"subnet-1234567890abcdef5" ,
]
Alternative Configurations
For development or staging environments, use a single shared NAT Gateway: module "vpc" {
source = "github.com/Planview/tf_aws_vpc"
name = "dev-vpc"
cidr = "10.0.0.0/16"
azs = [ "us-west-2a" , "us-west-2b" ]
private_subnets = [ "10.0.1.0/24" , "10.0.2.0/24" ]
public_subnets = [ "10.0.101.0/24" , "10.0.102.0/24" ]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
tags = {
Terraform = "true"
Environment = "development"
}
}
This reduces NAT Gateway costs by ~66% but sacrifices redundancy. Add database subnets for RDS or other database services: module "vpc" {
source = "github.com/Planview/tf_aws_vpc"
name = "production-vpc"
cidr = "10.0.0.0/16"
azs = [ "us-west-2a" , "us-west-2b" , "us-west-2c" ]
private_subnets = [ "10.0.1.0/24" , "10.0.2.0/24" , "10.0.3.0/24" ]
public_subnets = [ "10.0.101.0/24" , "10.0.102.0/24" , "10.0.103.0/24" ]
database_subnets = [ "10.0.201.0/24" , "10.0.202.0/24" , "10.0.203.0/24" ]
create_database_subnet_group = true
enable_nat_gateway = true
enable_dns_hostnames = true
tags = {
Terraform = "true"
Environment = "production"
}
}
output "database_subnet_group" {
value = module . vpc . database_subnet_group
}
Add S3 and DynamoDB VPC endpoints to reduce data transfer costs: module "vpc" {
source = "github.com/Planview/tf_aws_vpc"
name = "production-vpc"
cidr = "10.0.0.0/16"
azs = [ "us-west-2a" , "us-west-2b" , "us-west-2c" ]
private_subnets = [ "10.0.1.0/24" , "10.0.2.0/24" , "10.0.3.0/24" ]
public_subnets = [ "10.0.101.0/24" , "10.0.102.0/24" , "10.0.103.0/24" ]
enable_nat_gateway = true
enable_s3_endpoint = true
enable_dynamodb_endpoint = true
enable_dns_hostnames = true
tags = {
Terraform = "true"
Environment = "production"
}
}
VPC endpoints allow private connectivity to AWS services without traversing the internet or NAT Gateway. A comprehensive configuration with all features: module "vpc" {
source = "github.com/Planview/tf_aws_vpc"
name = "production-vpc"
cidr = "10.0.0.0/16"
azs = [ "us-west-2a" , "us-west-2b" , "us-west-2c" ]
private_subnets = [ "10.0.1.0/24" , "10.0.2.0/24" , "10.0.3.0/24" ]
public_subnets = [ "10.0.101.0/24" , "10.0.102.0/24" , "10.0.103.0/24" ]
database_subnets = [ "10.0.201.0/24" , "10.0.202.0/24" , "10.0.203.0/24" ]
elasticache_subnets = [ "10.0.211.0/24" , "10.0.212.0/24" , "10.0.213.0/24" ]
create_database_subnet_group = true
enable_nat_gateway = true
enable_dns_hostnames = true
enable_dns_support = true
enable_s3_endpoint = true
enable_dynamodb_endpoint = true
tags = {
Terraform = "true"
Environment = "production"
Project = "MyApp"
}
public_subnet_tags = {
Type = "Public"
}
private_subnet_tags = {
Type = "Private"
}
database_subnet_tags = {
Type = "Database"
}
}
Using Module Outputs
Once your VPC is deployed, you can use its outputs in other resources:
resource "aws_instance" "app" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
subnet_id = module . vpc . private_subnets [ 0 ]
vpc_security_group_ids = [ aws_security_group . app . id ]
tags = {
Name = "app-server"
}
}
resource "aws_db_instance" "main" {
identifier = "mydb"
engine = "postgres"
engine_version = "13.7"
instance_class = "db.t3.micro"
db_subnet_group_name = module . vpc . database_subnet_group
vpc_security_group_ids = [ aws_security_group . database . id ]
allocated_storage = 20
username = "dbadmin"
password = var . db_password
skip_final_snapshot = true
}
resource "aws_lb" "main" {
name = "app-alb"
internal = false
load_balancer_type = "application"
subnets = module . vpc . public_subnets
security_groups = [ aws_security_group . alb . id ]
tags = {
Name = "app-alb"
}
}
resource "aws_security_group" "app" {
name_prefix = "app-sg"
vpc_id = module . vpc . vpc_id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [ "10.0.0.0/16" ]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [ "0.0.0.0/0" ]
}
}
Available Outputs
The module provides these outputs that you can reference:
Output Description Example Usage vpc_idVPC ID Security group vpc_id vpc_cidr_blockVPC CIDR block Network planning private_subnetsPrivate subnet IDs EC2, ECS, Lambda public_subnetsPublic subnet IDs Load balancers, NAT database_subnetsDatabase subnet IDs RDS instances elasticache_subnetsElastiCache subnet IDs Redis, Memcached database_subnet_groupDB subnet group name RDS configuration elasticache_subnet_groupElastiCache subnet group name ElastiCache configuration natgw_idsNAT Gateway IDs Monitoring, cost tracking nat_eips_public_ipsNAT Gateway public IPs Whitelisting igw_idInternet Gateway ID Route table configuration public_route_table_idsPublic route table IDs Custom routes private_route_table_idsPrivate route table IDs Custom routes default_security_group_idDefault security group ID Security group rules vpc_endpoint_s3_idS3 VPC Endpoint ID Policy configuration vpc_endpoint_dynamodb_idDynamoDB VPC Endpoint ID Policy configuration
See the Outputs Reference for complete details.
Cleanup
To destroy the VPC and all associated resources:
This will permanently delete all resources created by the module. Ensure you have no running resources (EC2 instances, RDS databases, etc.) using the VPC before destroying it.
Next Steps
Configuration Options Explore all available configuration variables
Architecture Guide Understand the VPC architecture and design
Examples See more detailed deployment examples
Reference Complete input and output reference